package schedule;

import java.util.ArrayList;

import plan.Plan;
import start.Start;
import auftrag.Auftrag;
import auftrag.Produkt;
import auftrag.Ressource;

public class IterateVariants implements ISchedule {
	private long lMaxTime = 10000;
	double t = 10;
	int id = 0;
	
	@Override
	public Plan makePlan(ArrayList<?> pAuftragList,
			ArrayList<Ressource> pRessourceList) {
		//Sortiere die Aufträge nach EDF, dann nach Priorität
		Plan p = new Plan();
		ArrayList<Produkt> prodList = new ArrayList<Produkt>();
		if(Auftrag.class.isInstance(pAuftragList.get(0))){
			Auftrag aufAuftrag;
			ArrayList<Auftrag> arrSortAuftrag = new ArrayList<Auftrag>();
			for (int intIndexa = 0; intIndexa < pAuftragList.size(); intIndexa++) {
				aufAuftrag = (Auftrag) pAuftragList.get(intIndexa);
				if (arrSortAuftrag.isEmpty()) {
					arrSortAuftrag.add(aufAuftrag);
				} else {
					for (int intIndexb = 0; intIndexb < arrSortAuftrag.size(); intIndexb++) {
						if (aufAuftrag.getDeadline() < arrSortAuftrag
								.get(intIndexb).getDeadline()) {
							arrSortAuftrag.add(intIndexb, aufAuftrag);
							intIndexb = arrSortAuftrag.size();
						}
						else if (aufAuftrag.getDeadline() == arrSortAuftrag.get(
								intIndexb).getDeadline()
								&& aufAuftrag.getPriority() > arrSortAuftrag.get(
										intIndexb).getPriority()) {
							arrSortAuftrag.add(intIndexb, aufAuftrag);
							intIndexb = arrSortAuftrag.size();
						}
						else if((intIndexb+1) >= arrSortAuftrag.size() ){
							arrSortAuftrag.add(aufAuftrag);
							intIndexb = arrSortAuftrag.size();
						}
					}
				}
			}
			for(Auftrag a : arrSortAuftrag){
				prodList.addAll(a.getAuftragProdukte());
			}
		} else if(Produkt.class.isInstance(pAuftragList.get(0))){
			for(Object o : pAuftragList){
				prodList.add((Produkt)o);
			}
		}
		//SimplePlan fügt einfach eine Produktliste mit gewählten Varianten der Reihe nach in die Maschinen ein
		p = new SimplePlan().makePlan(prodList, pRessourceList);
		System.out.println("Intial plan's Quality: "+p.getQuality(false)+"\tt:"+t);
		int it = 0;
		int quality, nCountNothingChanged = 0;
		long lStart = System.currentTimeMillis();
		//solange die Qualität nicht 0 ist und t > 0.1
		while(System.currentTimeMillis()-lStart < lMaxTime && p.getQuality(false) > 250000 && nCountNothingChanged < 500){
			Start.it++;
			Plan pNeighbour;
			//alte Qualität
			quality = p.getQuality(false);
			//bestimme zufälliges Produkt
			int nProd = (int) (Math.random()*prodList.size());
			Produkt prodTemp =  prodList.get(nProd);
			
			//bestimme alte Variante für Rollback
			int oldVariant = prodTemp.getProduktVariante().indexOf(prodTemp.getChosenVariante());
			
			//wähle neue Variante
			prodTemp.chooseVariant(oldVariant+1, false);
			
			for(Ressource r : pRessourceList)
				r.clear();
			
			//neuer Plan
			pNeighbour = new SimplePlan().makePlan(prodList, pRessourceList);
			
			//falls neuer Plan besser: behalten
			if(pNeighbour.getQuality(true) < quality + t){
				p = pNeighbour;
				nCountNothingChanged = 0;
				
				if(p.getQuality(false) < quality)
					System.out.println((System.currentTimeMillis()-lStart)+" IV: Quality:"+p.getQuality(false)+"\tt:"+t);
			//sonst: Rollback, t verkleinern
			} else {
				prodTemp.chooseVariant(oldVariant, false);
				
				nCountNothingChanged++;
				if(nCountNothingChanged > 0 && nCountNothingChanged % 5 == 0)
					t=t*0.9;
				if(t < 0.1)
					t = 0;
				
				for(Ressource r : pRessourceList)
					r.clear();
			}
		}
		for(Ressource r : pRessourceList)
			r.clear();
		
		p = new SimplePlan().makePlan(prodList, pRessourceList);
		System.err.println("IV Iterations: "+it);
		return p;
	}
	
	public void setMaxTime(long t){
		lMaxTime = t;
	}
	
	public void setId(int id){
		this.id = id;
	}
	
	public void setTemperature(double t){
		this.t = t;
	}
}
